package fr.ece.ing4.si.multithread;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import fr.ece.ing4.si.gui.FirstWindow;

public class McSimulation2 {


	public double MonteCarloStandardOption (String CallPutFlag, double S, double X, double T, double r, double b, double v, int nSteps, int nSimulations) {
		
		//declarations
		double dt, St;
		double Sum=0, Drift, vSqrdt;
		int i, j, z=0;
		Random random;
	
		
		random = new Random ();
		
		dt = T/nSteps;
		Drift = (b-(v*v)/2) * dt;
		vSqrdt = v*Math.sqrt(dt);
		
		if(CallPutFlag.equals("c"))
		{
			z = 1;
		}
		else if(CallPutFlag.equals("p"))
		{
			z = -1;
		}
		
		
			St = S;
			for(j = 0; j < nSteps; j++)
			{
				St = St*Math.exp(Drift + vSqrdt * random.nextGaussian());
			}
			
			Sum = Sum + Math.max(z*(St-X), 0);
		
		return (Math.exp(-r*T) * (Sum/nSimulations));
		
	}
	
	public double McSimMulti () throws IOException, InterruptedException, ExecutionException{
		
		final int numberOfCores = Runtime.getRuntime().availableProcessors();
	    final double blockingCoefficient = 0.1;
	    final int poolSize = (int)(numberOfCores / (1 - blockingCoefficient));
	    
	    System.out.println("Number of Cores available is " + numberOfCores);
	    System.out.println("Pool size is " + poolSize);
	    
	  //File (sim.txt) reading
		final BufferedReader reader = new BufferedReader( new FileReader("sim.txt"));
			       
		final String data = reader.readLine(); //read one line
		
		final String[] dataItems = data.split(",");//put each data from the line in an array
		
		final List<Callable<Double>> var = new ArrayList<Callable<Double>>();
		
		for(int i=0; i<Integer.valueOf(dataItems[8]); i++){ //do the loop nSimulations time
			var.add(new Callable<Double> () {
				
				public Double call() throws Exception{
					//do a simulation
					return MonteCarloStandardOption(dataItems[0], Double.valueOf(dataItems[1]), Double.valueOf(dataItems[2]), Double.valueOf(dataItems[3]), Double.valueOf(dataItems[4]), Double.valueOf(dataItems[5]), Double.valueOf(dataItems[6]), Integer.valueOf(dataItems[7]), Integer.valueOf(dataItems[8]));
					
				}
				
			});
		}
		
		final ExecutorService executorPool = Executors.newFixedThreadPool(poolSize);    
		final List<Future<Double>> valueOfStocks = executorPool.invokeAll(var, 10000, TimeUnit.SECONDS);
			      
		double result = 0.0; 
			    for(final Future<Double> valueOfAStock : valueOfStocks)  
			      result += valueOfAStock.get(); 

			    executorPool.shutdown();
			    return result;   
		
	}

	public static void main(final String [] args) {
		javax.swing.SwingUtilities.invokeLater(new Runnable()
		{
			public void run()
			{
				//declarations
				FirstWindow win = new FirstWindow();
				//execution time
				long start;
				long end;
				
				start = System.currentTimeMillis();
				McSimulation2 mcsim = new McSimulation2();
				
				
				
				try {
					mcsim.McSimMulti();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} //do a MC simulation
 catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (ExecutionException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				end = System.currentTimeMillis();
				System.out.println("execution time: " + (end-start) + "ms");
			}
			
		});
		
		
	}
		

	
}
